"""总览页面视图函数业务逻辑模块"""
import traceback
from datetime import datetime, timedelta

import numpy as np
import pandas as pd

from air_web.config.config import config
from air_web.dw.data_mapping import DataType
from air_web.web_flask.bll.base_bll import BaseBll
from air_web.web_flask.common.constants import ReturnType


class AnalysisBll(BaseBll):
    """总览页面视图函数业务逻辑类"""

    time_field = "data_time"
    data_date_field = "data_date"
    cons_no_field = "cons_no"
    ORGNO_TYPEID_15MIN = config.get("ORGNO_TYPEID_15MIN", "orgno_typeid_15min")
    IS_TOTAL_MAX = config.get("is_total_max", True)

    def __init__(self):
        """
        如果当前页面用到mysql则init_mysql_dal=True，self.sql_dal就会提供mysql实例，不用到则传False
        如果当前页面用到es则init_es_dal=True，self.es_dal就会提供es实例，不用到则传False
        """
        super().__init__(
            init_mysql_dal=True, init_es_dal=True, init_cons_mysql_dal=True
        )
        self.today = datetime.now().strftime("%Y-%m-%d")
        self.year = str(datetime.now().year)

    def fill_data_with_null(self, res_df, start_date, end_date, is_one_day):
        """把数据填充到指定长度"""
        if is_one_day:
            date_format = "%Y-%m-%d %H:%M:%S"
            date_list = pd.date_range(
                start=start_date, periods=96, freq="15min"
            ).strftime(date_format)
            res_df[self.time_field] = pd.to_datetime(
                res_df[self.time_field]
            ).dt.strftime(date_format)
        else:
            date_format = "%Y-%m-%d"
            date_list = pd.date_range(
                start=start_date, end=end_date, freq="D"
            ).strftime(date_format)[:-1]
            res_df[self.time_field] = pd.to_datetime(
                res_df[self.time_field]
            ).dt.strftime(date_format)

        date_df = pd.DataFrame(date_list, columns=["data_time"])
        res_df = pd.merge(res_df, date_df, on="data_time", how="right")
        res_df = res_df.replace({np.nan: None})
        return res_df

    def query_sql_res(
        self,
        start_date,
        end_date,
        table_name,
        rules,
        doc_time_field,
        is_one_day,
        data_source="es",
        is_cons=False,
    ):
        res = self.ana_query_all(
            start_date,
            end_date,
            table_name,
            rules,
            data_source,
            doc_time_field,
            is_cons,
            is_one_day,
        )
        if not len(res):
            self.logger.warning(f"查询结果为空:{table_name}, {rules}")
            return res
        self.logger.info(f"查询:{table_name},结果数量:{len(res)}, {rules}")

        if "p_total_sum" in res:
            res = res.rename(
                columns={
                    "p_total_sum": "p_total",
                    "p_kt_sum": "p_kt",
                    "p_base_sum": "p_base",
                }
            )

        def gen_rate(x):
            try:
                return round(x["p_kt"] / x["p_total"], 4)
            except:
                return 0

        res["rate"] = res.apply(gen_rate, axis=1)

        res = self.fill_data_with_null(res, start_date, end_date, is_one_day)
        res.sort_values(by=[self.time_field], ascending=True, inplace=True)
        return res

    def get_date_rules(self, start_end, is_one_day):
        # 如果展示数据是今天，那么end_time取现在(因为用户计算结果中存了全天的预测点)
        if is_one_day and start_end[0].date() == datetime.now().date():
            end_date = datetime.now()
        else:
            end_date = start_end[1] + timedelta(days=1)

        date_rules = [
            (self.time_field, "query", ">=", str(start_end[0])),
            (self.time_field, "query", "<", str(end_date)),
        ]
        start_end[1] = end_date
        return date_rules

    def get_sql_res(
        self, cons_no, area_code, type_id, is_one_day, start_end1, start_end2
    ):
        date_rules_1 = self.get_date_rules(start_end1, is_one_day)
        date_rules_2 = self.get_date_rules(start_end2, is_one_day)

        if cons_no:
            cons_rules = [(self.cons_no_field, "query", "=", cons_no)]
            if self.data_source == "es":
                table_name = self.get_powerload_index(cons_no)
                is_day_max_list = [1, 3] if self.IS_TOTAL_MAX else [2, 3]
                is_max_rules = (
                    [("is_day_max", "query", "in", is_day_max_list)]
                    if not is_one_day
                    else []
                )

                rules1 = cons_rules + date_rules_1 + is_max_rules
                rules2 = cons_rules + date_rules_2 + is_max_rules

                res1 = self.query_sql_res(
                    start_end1[0],
                    start_end1[1],
                    table_name,
                    rules1,
                    self.time_field,
                    is_one_day,
                    data_source=self.data_source,
                    is_cons=True,
                )
                res2 = self.query_sql_res(
                    start_end2[0],
                    start_end2[1],
                    table_name,
                    rules2,
                    self.time_field,
                    is_one_day,
                    data_source=self.data_source,
                    is_cons=True,
                )
            else:
                date_rules_1 = [
                    ("data_date", "query", ">=", str(start_end1[0])),
                    ("data_date", "query", "<", str(start_end1[1])),
                ]
                date_rules_2 = [
                    ("data_date", "query", ">=", str(start_end2[0])),
                    ("data_date", "query", "<", str(start_end2[1])),
                ]

                if is_one_day:
                    table_name = config.get(
                        "ACLR_RES_POWER_96", "aclr_res_power_96"
                    )

                    data_type_rules = [
                        (
                            "data_type",
                            "query",
                            "in",
                            [DataType.P_TOTAL, DataType.P_KT],
                        )
                    ]
                    rules1 = cons_rules + date_rules_1 + data_type_rules
                    rules2 = cons_rules + date_rules_2 + data_type_rules
                    res1 = self.query_sql_res(
                        start_end1[0],
                        start_end1[1],
                        table_name,
                        rules1,
                        self.time_field,
                        is_one_day,
                        data_source=self.data_source,
                        is_cons=True,
                    )
                    res2 = self.query_sql_res(
                        start_end2[0],
                        start_end2[1],
                        table_name,
                        rules2,
                        self.time_field,
                        is_one_day,
                        data_source=self.data_source,
                        is_cons=True,
                    )
                else:
                    table_name = config.get("CONS_YMD_STAT", "cons_ymd_stat")

                    rules1 = cons_rules + date_rules_1
                    rules2 = cons_rules + date_rules_2
                    res1 = self.query_sql_res(
                        start_end1[0],
                        start_end1[1],
                        table_name,
                        rules1,
                        self.time_field,
                        is_one_day,
                        data_source=self.data_source,
                        is_cons=True,
                    )
                    res2 = self.query_sql_res(
                        start_end2[0],
                        start_end2[1],
                        table_name,
                        rules2,
                        self.time_field,
                        is_one_day,
                        data_source=self.data_source,
                        is_cons=True,
                    )
        else:
            table_name = self.ORGNO_TYPEID_15MIN
            type_id_rules = (
                [("type_id", "query", "=", type_id)]
                if type_id
                else [("type_id", "query", "=", "0")]
            )
            is_max_rules = (
                [("is_day_max", "query", "=", 1)] if not is_one_day else []
            )
            rules1 = (
                [("org_no", "query", "=", area_code)]
                + date_rules_1
                + type_id_rules
                + is_max_rules
            )
            rules2 = (
                [("org_no", "query", "=", area_code)]
                + date_rules_2
                + type_id_rules
                + is_max_rules
            )
            res1 = self.query_sql_res(
                start_end1[0],
                start_end1[1],
                table_name,
                rules1,
                self.time_field,
                is_one_day,
                data_source="mysql",
            )
            res2 = self.query_sql_res(
                start_end2[0],
                start_end2[1],
                table_name,
                rules2,
                self.time_field,
                is_one_day,
                data_source="mysql",
            )

        return [
            {
                "name": "时间区间一",
                "date_list": list(res1[self.time_field]) if len(res1) else [],
                "p_total": list(res1["p_total"]) if len(res1) else [],
                "p_kt": list(res1["p_kt"]) if len(res1) else [],
                "rate": list(res1["rate"]) if len(res1) else [],
            },
            {
                "name": "时间区间二",
                "date_list": list(res2[self.time_field]) if len(res2) else [],
                "p_total": list(res2["p_total"]) if len(res2) else [],
                "p_kt": list(res2["p_kt"]) if len(res2) else [],
                "rate": list(res2["rate"]) if len(res2) else [],
            },
        ]

    def get_air_huanbi(self, params):
        """
        查询电站信息
        :return: dict
        """
        try:
            cons_no = params.get("cons_no")
            area_code = params.get("area_code")
            type_id = params.get("type_id")
            days = params.get("days", 30) - 1
            is_one_day = True if days == 0 else False
            end_date_1 = datetime.strptime(
                params.get("end_date_1"), "%Y-%m-%d"
            )
            end_date_2 = datetime.strptime(
                params.get("end_date_2"), "%Y-%m-%d"
            )
            start_date_1 = end_date_1 - timedelta(days=days)
            start_date_2 = end_date_2 - timedelta(days=days)

            res = self.get_sql_res(
                cons_no,
                area_code,
                type_id,
                is_one_day,
                [start_date_1, end_date_1],
                [start_date_2, end_date_2],
            )

            return res
        except:
            self.logger.error(traceback.format_exc())
            return ReturnType.ERROR

    def get_air_tongbi(self, params):
        """
        查询电站信息
        :return: dict
        """
        try:
            cons_no = params.get("cons_no")
            area_code = params.get("area_code")
            type_id = params.get("type_id")
            start_date_2 = datetime.strptime(
                params.get("start_date"), "%Y-%m-%d"
            )
            end_date_2 = datetime.strptime(params.get("end_date"), "%Y-%m-%d")
            is_one_day = True if start_date_2 == end_date_2 else False

            start_date_1 = start_date_2.replace(year=start_date_2.year - 1)
            end_date_1 = end_date_2.replace(year=end_date_2.year - 1)

            res = self.get_sql_res(
                cons_no,
                area_code,
                type_id,
                is_one_day,
                [start_date_1, end_date_1],
                [start_date_2, end_date_2],
            )
            return res
        except:
            self.logger.error(traceback.format_exc())
            return ReturnType.ERROR
